﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace ExcelFileQueryTool
{
    public partial class frmWorkLogImageProcess : Form
    {
        Point _startPosition = Point.Empty;
        Point _endPosition = Point.Empty;
        bool _inSelectRegionMode = false;
        const int REGION_MIN_WIDTH = 20;
        const int REGION_MIN_HEIGHT = 20;
        string _oriImgExtension = null;

        // dispose in 'Dispose' method
        Brush _brush = new SolidBrush(Color.FromArgb(20, Color.Yellow.R, Color.Yellow.G, Color.Yellow.B));
        // dispose in 'Dispose' method
        Image _oriImage = null;

        public frmWorkLogImageProcess()
        {
            InitializeComponent();

            // double buffer
            this.SetStyle(
                  ControlStyles.AllPaintingInWmPaint |
                  ControlStyles.UserPaint |
                  ControlStyles.DoubleBuffer, true);
        }

        private void LoadImage(string file)
        {
            picImage.Image = Image.FromFile(file);
            _oriImage = picImage.Image.Clone() as Image;
            _oriImgExtension = Path.GetExtension(file);
        }

        private bool IsImageReady()
        {
            return picImage.Image != null;
        }

        private Rectangle GetImageRectangle()
        {
            var rect = picImage.ClientRectangle;
            var padding = picImage.Padding;

            rect.X += padding.Left;
            rect.Y += padding.Top;
            rect.Width -= padding.Horizontal;
            rect.Height -= padding.Vertical;

            var size = picImage.Image.Size;
            var zoomSize = picImage.ClientSize;
            float ratio = Math.Min((float)zoomSize.Width / size.Width, (float)zoomSize.Height / size.Height);
            rect.Width = (int)(size.Width * ratio);
            rect.Height = (int)(size.Height * ratio);
            rect.X = (picImage.ClientRectangle.Width - rect.Width) / 2;
            rect.Y = (picImage.ClientRectangle.Height - rect.Height) / 2;

            return rect;
        }

        private static int Scale(int value, float scale, int maxValue)
        {
            int result = (int)(value * scale);
            return result < 0 ? 0 : result > maxValue ? maxValue : result;
        }

        private void picImage_MouseDown(object sender, MouseEventArgs e)
        {
            if (IsImageReady() == false)
                return;

            _startPosition = e.Location;
        }

        private void picImage_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsImageReady() == false)
                return;

            if (e.Button != MouseButtons.Left)
                return;

            if (_startPosition == Point.Empty)
                return;

            var width = e.Location.X - _startPosition.X;
            var height = e.Location.Y - _startPosition.Y;

            if (width < REGION_MIN_WIDTH || height < REGION_MIN_HEIGHT)
                return;

            _endPosition = e.Location;
            _inSelectRegionMode = true;
            picImage.Invalidate();
        }

        private void picImage_MouseUp(object sender, MouseEventArgs e)
        {
            _inSelectRegionMode = false;
        }

        private void picImage_MouseLeave(object sender, EventArgs e)
        {
            Cursor = Cursors.Default;
        }

        private void picImage_Paint(object sender, PaintEventArgs e)
        {
            if (_inSelectRegionMode == false)
                return;

            var x = _startPosition.X;
            var y = _startPosition.Y;
            var width = _endPosition.X - _startPosition.X;
            var height = _endPosition.Y - _startPosition.Y;

            e.Graphics.FillRectangle(_brush, x, y, width, height);
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog diag = new OpenFileDialog())
            {
                diag.CheckFileExists = true;

                if (diag.ShowDialog() == DialogResult.OK)
                {
                    LoadImage(diag.FileName);
                }
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (IsImageReady() == false)
                return;

            string fileName = null;

            using (SaveFileDialog diag = new SaveFileDialog())
            {
                diag.Filter = "图片(*" + _oriImgExtension + ")|*" + _oriImgExtension;
                diag.CheckPathExists = true;

                if (diag.ShowDialog() == DialogResult.OK)
                {
                    fileName = diag.FileName;
                }
            }

            if (string.IsNullOrEmpty(fileName))
                return;

            picImage.Image.Save(fileName);
        }

        private void trackBrightness_Scroll(object sender, EventArgs e)
        {
            int threshold = trackBrightness.Value;
            int width = picImage.Image.Width;
            int height = picImage.Image.Height;

            float brightnessFactor = (float)threshold / 100;
            Rectangle bounds = new Rectangle(0, 0, width, height);

            ColorMatrix colorMatrix =
                new ColorMatrix(
                    new[]
                        {
                            new float[] { 1, 0, 0, 0, 0 },
                            new float[] { 0, 1, 0, 0, 0 },
                            new float[] { 0, 0, 1, 0, 0 },
                            new float[] { 0, 0, 0, 1, 0 },
                            new[] { brightnessFactor, brightnessFactor, brightnessFactor, 0, 1 }
                        });

            using (Graphics graphics = Graphics.FromImage(_oriImage))
            {
                using (ImageAttributes imageAttributes = new ImageAttributes())
                {
                    imageAttributes.SetColorMatrix(colorMatrix);
                    graphics.DrawImage(picImage.Image, bounds, 0, 0, width, height, GraphicsUnit.Pixel, imageAttributes);
                }
            }

            picImage.Image = _oriImage;
        }

        private void trackContrast_Scroll(object sender, EventArgs e)
        {
            int threshold = trackContrast.Value;
            int width = picImage.Image.Width;
            int height = picImage.Image.Height;

            Rectangle bounds = new Rectangle(0, 0, width, height);
            float contrastFactor = (float)threshold / 100;

            // Stop at -1 to prevent inversion.
            contrastFactor++;
            float factorTransform = 0.5f * (1.0f - contrastFactor);

            ColorMatrix colorMatrix =
                new ColorMatrix(
                    new[]
                    {
                        new[] { contrastFactor, 0, 0, 0, 0 },
                        new[] { 0, contrastFactor, 0, 0, 0 },
                        new[] { 0, 0, contrastFactor, 0, 0 },
                        new float[] { 0, 0, 0, 1, 0 },
                        new[] { factorTransform, factorTransform, factorTransform, 0, 1 }
                    });

            using (Graphics graphics = Graphics.FromImage(_oriImage))
            {
                using (ImageAttributes imageAttributes = new ImageAttributes())
                {
                    imageAttributes.SetColorMatrix(colorMatrix);
                    graphics.DrawImage(picImage.Image, bounds, 0, 0, width, height, GraphicsUnit.Pixel, imageAttributes);
                }
            }

            picImage.Image = _oriImage;
        }

        private void btnCrop_Click(object sender, EventArgs e)
        {
            if (_startPosition == Point.Empty)
                return;

            var imageRect = GetImageRectangle();
            float scaleX = (float)picImage.Image.Width / imageRect.Width;
            float scaleY = (float)picImage.Image.Height / imageRect.Height;

            var cropRect = new Rectangle();
            cropRect.X = Scale(_startPosition.X - imageRect.X, scaleX, picImage.Image.Width);
            cropRect.Y = Scale(_startPosition.Y - imageRect.Y, scaleY, picImage.Image.Height);
            cropRect.Width = Scale(_endPosition.X - _startPosition.X, scaleX, picImage.Image.Width - cropRect.X);
            cropRect.Height = Scale(_endPosition.Y - _startPosition.Y, scaleY, picImage.Image.Height - cropRect.Y);

            var result = new Bitmap(cropRect.Width, cropRect.Height, picImage.Image.PixelFormat);
            using (var g = Graphics.FromImage(result))
            {
                g.DrawImage(picImage.Image, new Rectangle(new Point(0, 0), cropRect.Size), cropRect, GraphicsUnit.Pixel);

            }

            picImage.Image = result;
            _oriImage = picImage.Image.Clone() as Image;
        }
    }
}
